﻿using BJoin.Application.BObject;
using BJoin.Application.Entity;
using BJoin.DapperExtension.DatabaseFactory;
using BJoin.DapperExtension.Postgresql.TypeHandler;
using Dapper;
using DapperExtensions;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BJoin.Application.IRepository
{
    public abstract class BaseRepository<T> : IBaseRepository<T> where T : BaseEntity
    {

        protected BaseRepository(ILogger<BaseRepository<T>> logger, IDbFactory<IDatabase, long?> factory)
        {
            SqlMapper.AddTypeHandler(typeof(int[]), new ArrayTypeHandler<int>());
            SqlMapper.AddTypeHandler(typeof(long[]), new ArrayTypeHandler<long>());
            SqlMapper.AddTypeHandler(typeof(decimal[]), new ArrayTypeHandler<decimal>());
            //....
        }
        #region 异步
        public virtual async Task<long> CountAsync(IDatabase database, object predicate = null)
        {
            return await database.CountAsync<T>(predicate);
        }
        public virtual async Task<long> CountByComplexSqlAsync(IDatabase database, string sql, object param = null)
        {
            return await database.CountByComplexSqlAsync(sql, param);
        }
        public virtual async Task<Page<T>> GetListPagingAsync(IDatabase database, int pageNumber, int recordsPerPage, object predicate = null, string[] sorts = null)
        {
            return await database.GetPagesAsync<T>(pageNumber, recordsPerPage, predicate, RepositoryExtension.OrderByToSort<T>(sorts));
        }

        public virtual async Task<IEnumerable<T>> GetListAsync(IDatabase database, int? firstResult, int? maxResults, object predicate = null, string[] sorts = null)
        {
            if (firstResult.HasValue && maxResults.HasValue)
                return await database.GetSetAsync<T>(predicate, RepositoryExtension.OrderByToSort<T>(sorts), firstResult.Value, maxResults.Value);
            else
                return await database.GetListAsync<T>(predicate, RepositoryExtension.OrderByToSort<T>(sorts));
        }

        public virtual async Task<IEnumerable<TR>> GetListByComplexSqlAsync<TR>(IDatabase database, string sql, object param = null) where TR : class
        {
            return await database.GetListByComplexSqlAsync<TR>(sql, param);
        }
        public virtual async Task<Page<TR>> GetListPagingByComplexSqlAsync<TR>(IDatabase database, int pageNumber, int recordsPerPage, string sql, object param = null) where TR : class
        {
            return await database.GetPagesByComplexSqlAsync<TR>(sql, param, pageNumber, recordsPerPage);
        }
        public virtual async Task<bool> InsertAsync(IDatabase database, T entity)
        {
            await database.InsertAsync(entity);
            return await Task.FromResult(true);
        }
        public virtual async Task<bool> InsertManyAsync(IDatabase database, IEnumerable<T> entities)
        {
            await database.InsertAsync(entities);
            return await Task.FromResult(true);
        }
        public virtual async Task<bool> UpdateAsync(IDatabase database, T entity, object predicate)
        {
            return await database.UpdateAsync<T>(entity, predicate);
        }
        public virtual async Task<bool> UpdateSetAsync(IDatabase database, T entity, object predicate)
        {
            return await database.UpdateSetAsync<T>(entity, predicate);
        }
        public virtual async Task<bool> DeleteAsync(IDatabase database, object predicate = null)
        {
            predicate.ValidateObjectNotNull();
            return await database.DeleteAsync<T>(predicate);
        }
        public virtual async Task<int> ExecuteAsync(IDatabase database, string sql, object param = null)
        {
            return await database.ExecuteAsync(sql, param);
        }
        #endregion
    }
    public abstract class BaseRepository<T, TKey> : IBaseRepository<T, TKey> where T : BaseEntity<TKey>
    {

        protected BaseRepository(ILogger<BaseRepository<T, TKey>> logger, IDbFactory<IDatabase, long?> factory)
        {
            SqlMapper.AddTypeHandler(typeof(int[]), new ArrayTypeHandler<int>());
            SqlMapper.AddTypeHandler(typeof(long[]), new ArrayTypeHandler<long>());
            SqlMapper.AddTypeHandler(typeof(decimal[]), new ArrayTypeHandler<decimal>());
            //....
        }
        #region 异步
        public virtual async Task<long> CountAsync(IDatabase database, object predicate = null)
        {
            return await database.CountAsync<T>(predicate);
        }
        public virtual async Task<long> CountByComplexSqlAsync(IDatabase database, string sql, object param = null)
        {
            return await database.CountByComplexSqlAsync(sql, param);
        }
        public virtual async Task<T> GetAsync(IDatabase database, TKey id)
        {
            return await database.GetAsync<T>(id);
        }
        public virtual async Task<Page<T>> GetListPagingAsync(IDatabase database, int pageNumber, int recordsPerPage, object predicate = null, string[] sorts = null)
        {
            return await database.GetPagesAsync<T>(pageNumber, recordsPerPage, predicate, RepositoryExtension.OrderByToSort<T>(sorts));
        }

        public virtual async Task<IEnumerable<T>> GetListAsync(IDatabase database, int? firstResult, int? maxResults, object predicate = null, string[] sorts = null)
        {
            if (firstResult.HasValue && maxResults.HasValue)
                return await database.GetSetAsync<T>(predicate, RepositoryExtension.OrderByToSort<T>(sorts), firstResult.Value, maxResults.Value);
            else
                return await database.GetListAsync<T>(predicate, RepositoryExtension.OrderByToSort<T>(sorts));
        }

        public virtual async Task<IEnumerable<TR>> GetListByComplexSqlAsync<TR>(IDatabase database, string sql, object param = null) where TR : class
        {
            return await database.GetListByComplexSqlAsync<TR>(sql, param);
        }
        public virtual async Task<Page<TR>> GetListPagingByComplexSqlAsync<TR>(IDatabase database, int pageNumber, int recordsPerPage, string sql, object param = null) where TR : class
        {
            return await database.GetPagesByComplexSqlAsync<TR>(sql, param, pageNumber, recordsPerPage);
        }
        public virtual async Task<TKey> InsertAsync(IDatabase database, T entity)
        {
            return await database.InsertAsync(entity);
        }
        public virtual async Task<IEnumerable<TKey>> InsertManyAsync(IDatabase database, IEnumerable<T> entities)
        {
            await database.InsertAsync(entities);
            return entities.Select(e => e.Id);
        }
        public virtual async Task<bool> UpdateAsync(IDatabase database, T entity, object predicate)
        {
            return await database.UpdateAsync<T>(entity, predicate);
        }
        public virtual async Task<bool> UpdateSetAsync(IDatabase database, T entity, object predicate)
        {
            return await database.UpdateSetAsync<T>(entity, predicate);
        }
        public virtual async Task<bool> DeleteAsync(IDatabase database, TKey[] id)
        {
            return await database.DeleteAsync<T>(new { Id = id });
        }
        public virtual async Task<bool> DeleteAsync(IDatabase database, object predicate = null)
        {
            predicate.ValidateObjectNotNull();
            return await database.DeleteAsync<T>(predicate);
        }
        public virtual async Task<int> ExecuteAsync(IDatabase database, string sql, object param = null)
        {
            return await database.ExecuteAsync(sql, param);
        }
        #endregion
    }
    public abstract class BaseRepository<T, TKey, TExt> : IBaseRepository<T, TKey, TExt> where T : BaseEntity<TKey, TExt> where TExt : BObjExt
    {

        protected BaseRepository(ILogger<BaseRepository<T, TKey, TExt>> logger, IDbFactory<IDatabase, long?> factory)
        {
            SqlMapper.AddTypeHandler(typeof(TExt), new JsonTypeHandler<TExt>());
            SqlMapper.AddTypeHandler(typeof(int[]), new ArrayTypeHandler<int>());
            SqlMapper.AddTypeHandler(typeof(long[]), new ArrayTypeHandler<long>());
            SqlMapper.AddTypeHandler(typeof(decimal[]), new ArrayTypeHandler<decimal>());
            //....
        }
        #region 异步
        public virtual async Task<long> CountAsync(IDatabase database, object predicate = null)
        {
            return await database.CountAsync<T>(predicate);
        }
        public virtual async Task<long> CountByComplexSqlAsync(IDatabase database, string sql, object param = null)
        {
            return await database.CountByComplexSqlAsync(sql, param);
        }
        public virtual async Task<T> GetAsync(IDatabase database, TKey id)
        {
            return await database.GetAsync<T>(id);
        }
        public virtual async Task<Page<T>> GetListPagingAsync(IDatabase database, int pageNumber, int recordsPerPage, object predicate = null, string[] sorts = null)
        {
            return await database.GetPagesAsync<T>(pageNumber, recordsPerPage, predicate, RepositoryExtension.OrderByToSort<T>(sorts));
        }

        public virtual async Task<IEnumerable<T>> GetListAsync(IDatabase database, int? firstResult, int? maxResults, object predicate = null, string[] sorts = null)
        {
            if(firstResult.HasValue && maxResults.HasValue)
                return await database.GetSetAsync<T>(predicate, RepositoryExtension.OrderByToSort<T>(sorts), firstResult.Value, maxResults.Value);
            else
                return await database.GetListAsync<T>(predicate, RepositoryExtension.OrderByToSort<T>(sorts));
        }

        public virtual async Task<IEnumerable<TR>> GetListByComplexSqlAsync<TR>(IDatabase database, string sql, object param = null) where TR : class
        {
            return await database.GetListByComplexSqlAsync<TR>(sql, param);
        }
        public virtual async Task<Page<TR>> GetListPagingByComplexSqlAsync<TR>(IDatabase database, int pageNumber, int recordsPerPage, string sql, object param = null) where TR : class
        {
            return await database.GetPagesByComplexSqlAsync<TR>(sql, param, pageNumber, recordsPerPage);
        }
        public virtual async Task<TKey> InsertAsync(IDatabase database, T entity)
        {
            return await database.InsertAsync(entity);
        }
        public virtual async Task<IEnumerable<TKey>> InsertManyAsync(IDatabase database, IEnumerable<T> entities)
        {
            await database.InsertAsync(entities);
            return entities.Select(e => e.Id);
        }
        public virtual async Task<bool> UpdateAsync(IDatabase database, T entity, object predicate)
        {
            return await database.UpdateAsync<T>(entity, predicate);
        }
        public virtual async Task<bool> UpdateSetAsync(IDatabase database, T entity, object predicate)
        {
            return await database.UpdateSetAsync<T>(entity, predicate);
        }
        public virtual async Task<bool> DeleteAsync(IDatabase database, TKey[] id)
        {
            return await database.DeleteAsync<T>(new { Id = id });
        }
        public virtual async Task<bool> DeleteAsync(IDatabase database, object predicate = null)
        {
            predicate.ValidateObjectNotNull();
            return await database.DeleteAsync<T>(predicate);
        }
        public virtual async Task<int> ExecuteAsync(IDatabase database, string sql, object param = null)
        {
            return await database.ExecuteAsync(sql, param);
        }
        #endregion
    }
}
